package org.apache.zookeeper.server.paxos2;


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedList;

/**
 * Created by IntelliJ IDEA.
 * User: iodine
 * Date: Aug 6, 2011
 * Time: 11:53:39 AM
 * To change this template use File | Settings | File Templates.
 */
public class MetaIndex {
    public static final int gap = 100;
    private final String path;
    private final boolean readonly;

    //These are used for write
    private LinkedList<Long> indexList = null;
    private int count = 0;

    //These are used for read
    private long[] index = null;

    public MetaIndex(String path, boolean readonly) {
        this.path = path;
        this.readonly = readonly;
        if (readonly) {
            try {
                FileInputStream fis = new FileInputStream(path);
                byte[] data = new byte[fis.available()];
                fis.read(data);
                ByteBuffer b = ByteBuffer.wrap(data);
                index = new long[data.length / 8];
                for (int i = 0; i < index.length; i++)
                    index[i] = b.getLong();
                fis.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        } else
            indexList = new LinkedList<Long>();
    }

    public void write(long blockNo) {
        if (readonly)
            throw new RuntimeException("This should not happen");
        if (count % gap == 0)
            indexList.addLast(blockNo);
        count++;
    }

    public void flush() {
        if (readonly)
            throw new RuntimeException("This should not happen");
        try {
            FileOutputStream fos = new FileOutputStream(path);
            byte[] out = new byte[indexList.size() * 8];
            ByteBuffer b = ByteBuffer.wrap(out);
            for (Long blockNo : indexList) {
                b.putLong(blockNo);
            }
            indexList.clear();
            fos.write(out);
            fos.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    //May have false positive, but should have no false negative
    public boolean isIn() {
        if (!readonly)
            throw new RuntimeException("This should not happen");
        return true;
    }

    public int getStartIndex(long blockNo) {
        if (!readonly)
            throw new RuntimeException("This should not happen");
        int position = Arrays.binarySearch(index, blockNo);
        if (position >= 0)
            return position;
        else if (position == -1)
	    return -1;
	else
            return -(position + 1)-1;

    }


}


